home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 34
/
Amiga Format CD34 (1998-11-20)(Future Publishing)(GB)[!][Christmas issue].iso
/
-seriously_amiga-
/
programming
/
c
/
mesa-2.6
/
src
/
vbrender.c
< prev
Wrap
C/C++ Source or Header
|
1998-10-01
|
39KB
|
1,259 lines
/* $Id: vbrender.c,v 1.21 1998/01/18 15:04:48 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 2.6
* Copyright (C) 1995-1997 Brian Paul
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* vbrender.c
*
* Modified 27 Jun 1998
* by Jarno van der Linden
* jarno@kcbbs.gen.nz
*
* Based on vbrender.c ver 1.21
* Some minor changes to work around SAS/C 6.59 optimizer bug
*
*/
/*
* Render points, lines, and polygons. The only entry point to this
* file is the gl_render_vb() function. This function is called after
* the vertex buffer has filled up or glEnd() has been called.
*
* This file basically only makes calls to the clipping functions and
* the point, line and triangle rasterizers via the function pointers.
* context->Driver.PointsFunc()
* context->Driver.LineFunc()
* context->Driver.TriangleFunc()
*/
#ifdef PC_HEADER
#include "all.h"
#else
#include "clip.h"
#include "context.h"
#include "light.h"
#include "macros.h"
#include "matrix.h"
#include "pb.h"
#include "types.h"
#include "vb.h"
#include "vbrender.h"
#include "xform.h"
#endif
/*
* This file implements rendering of points, lines and polygons defined by
* vertices in the vertex buffer.
*/
#ifdef PROFILE
# define START_PROFILE \
{ \
GLdouble t0 = gl_time();
# define END_PROFILE( TIMER, COUNTER, INCR ) \
TIMER += (gl_time() - t0); \
COUNTER += INCR; \
}
#else
# define START_PROFILE
# define END_PROFILE( TIMER, COUNTER, INCR )
#endif
/*
* Render a line segment from VB[v1] to VB[v2] when either one or both
* endpoints must be clipped.
*/
static void render_clipped_line( GLcontext *ctx, GLuint v1, GLuint v2 )
{
GLfloat ndc_x, ndc_y, ndc_z;
GLuint provoking_vertex;
struct vertex_buffer *VB = ctx->VB;
/* which vertex dictates the color when flat shading: */
provoking_vertex = v2;
/*
* Clipping may introduce new vertices. New vertices will be stored
* in the vertex buffer arrays starting with location VB->Free. After
* we've rendered the line, these extra vertices can be overwritten.
*/
VB->Free = VB_MAX;
/* Clip against user clipping planes */
if (ctx->Transform.AnyClip) {
GLuint orig_v1 = v1, orig_v2 = v2;
if (gl_userclip_line( ctx, &v1, &v2 )==0)
return;
/* Apply projection matrix: clip = Proj * eye */
if (v1!=orig_v1) {
TRANSFORM_POINT( VB->Clip[v1], ctx->ProjectionMatrix, VB->Eye[v1] );
}
if (v2!=orig_v2) {
TRANSFORM_POINT( VB->Clip[v2], ctx->ProjectionMatrix, VB->Eye[v2] );
}
}
/* Clip against view volume */
if (gl_viewclip_line( ctx, &v1, &v2 )==0)
return;
/* Transform from clip coords to ndc: ndc = clip / W */
if (VB->Clip[v1][3] != 0.0F) {
GLfloat wInv = 1.0F / VB->Clip[v1][3];
ndc_x = VB->Clip[v1][0] * wInv;
ndc_y = VB->Clip[v1][1] * wInv;
ndc_z = VB->Clip[v1][2] * wInv;
}
else {
/* Can't divide by zero, so... */
ndc_x = ndc_y = ndc_z = 0.0F;
}
/* Map ndc coord to window coords. */
VB->Win[v1][0] = ndc_x * ctx->Viewport.Sx + ctx->Viewport.Tx;
VB->Win[v1][1] = ndc_y * ctx->Viewport.Sy + ctx->Viewport.Ty;
VB->Win[v1][2] = ndc_z * ctx->Viewport.Sz + ctx->Viewport.Tz;
/* Transform from clip coords to ndc: ndc = clip / W */
if (VB->Clip[v2][3] != 0.0F) {
GLfloat wInv = 1.0F / VB->Clip[v2][3];
ndc_x = VB->Clip[v2][0] * wInv;
ndc_y = VB->Clip[v2][1] * wInv;
ndc_z = VB->Clip[v2][2] * wInv;
}
else {
/* Can't divide by zero, so... */
ndc_x = ndc_y = ndc_z = 0.0F;
}
/* Map ndc coord to window coords. */
VB->Win[v2][0] = ndc_x * ctx->Viewport.Sx + ctx->Viewport.Tx;
VB->Win[v2][1] = ndc_y * ctx->Viewport.Sy + ctx->Viewport.Ty;
VB->Win[v2][2] = ndc_z * ctx->Viewport.Sz + ctx->Viewport.Tz;
if (ctx->Driver.RasterSetup) {
/* Device driver rasterization setup */
(*ctx->Driver.RasterSetup)( ctx, v1, v1+1 );
(*ctx->Driver.RasterSetup)( ctx, v2, v2+1 );
}
START_PROFILE
(*ctx->Driver.LineFunc)( ctx, v1, v2, provoking_vertex );
END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
}
/*
* Compute Z offsets for a polygon with plane defined by (A,B,C,D)
* D is not needed.
*/
static void offset_polygon( GLcontext *ctx, GLfloat a, GLfloat b, GLfloat c )
{
GLfloat ac, bc, m;
GLfloat offset;
if (c<0.001F && c>-0.001F) {
/* to prevent underflow problems */
offset = 0.0F;
}
else {
ac = a / c;
bc = b / c;
if (ac<0.0F) ac = -ac;
if (bc<0.0F) bc = -bc;
m = MAX2( ac, bc );
/* m = sqrt( ac*ac + bc*bc ); */
offset = m * ctx->Polygon.OffsetFactor + ctx->Polygon.OffsetUnits;
}
ctx->PointZoffset = ctx->Polygon.OffsetPoint ? offset : 0.0F;
ctx->LineZoffset = ctx->Polygon.OffsetLine ? offset : 0.0F;
ctx->PolygonZoffset = ctx->Polygon.OffsetFill ? offset : 0.0F;
}
/*
* When glPolygonMode() is used to specify that the front/back rendering
* mode for polygons is not GL_FILL we end up calling this function.
*/
static void unfilled_polygon( GLcontext *ctx,
GLuint n, GLuint vlist[],
GLuint pv, GLuint facing )
{
GLenum mode = facing ? ctx->Polygon.BackMode : ctx->Polygon.FrontMode;
struct vertex_buffer *VB = ctx->VB;
if (mode==GL_POINT) {
GLint i, j;
GLboolean edge;
if ( ctx->Primitive==GL_TRIANGLES
|| ctx->Primitive==GL_QUADS
|| ctx->Primitive==GL_POLYGON) {
edge = GL_FALSE;
}
else {
edge = GL_TRUE;
}
for (i=0;i<n;i++) {
j = vlist[i];
if (edge || VB->Edgeflag[j]) {
(*ctx->Driver.PointsFunc)( ctx, j, j );
}
}
}
else if (mode==GL_LINE) {
GLuint i, j0, j1;
GLboolean edge;
ctx->StippleCounter = 0;
if ( ctx->Primitive==GL_TRIANGLES
|| ctx->Primitive==GL_QUADS
|| ctx->Primitive==GL_POLYGON) {
edge = GL_FALSE;
}
else {
edge = GL_TRUE;
}
/* draw the edges */
for (i=0;i<n;i++) {
j0 = (i==0) ? vlist[n-1] : vlist[i-1];
j1 = vlist[i];
if (edge || VB->Edgeflag[j0]) {
START_PROFILE
(*ctx->Driver.LineFunc)( ctx, j0, j1, pv );
END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
}
}
}
else {
/* Fill the polygon */
GLuint j0, i, j;
j0 = vlist[0];
for (i=2;i<n;i++) {
j = i-1;
START_PROFILE
(*ctx->Driver.TriangleFunc)( ctx, j0, vlist[j], vlist[j+1], pv );
END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
}
}
}
/*
* Compute signed area of the n-sided polgyon specified by vertices vb->Win[]
* and vertex list vlist[].
* A clockwise polygon will return a negative area.
* A counter-clockwise polygon will return a positive area.
*/
static GLfloat polygon_area( const struct vertex_buffer *vb,
GLuint n, const GLuint vlist[] )
{
GLfloat area = 0.0F;
GLint i;
for (i=0;i<n;i++) {
/* area = sum of trapezoids */
GLuint j0 = vlist[i];
GLuint j1 = vlist[(i+1)%n];
GLfloat x0 = vb->Win[j0][0];
GLfloat y0 = vb->Win[j0][1];
GLfloat x1 = vb->Win[j1][0];
GLfloat y1 = vb->Win[j1][1];
GLfloat trapArea = (x0-x1)*(y0+y1); /* Note: no divide by two here! */
area += trapArea;
}
re